﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace katOS
{
    /// <summary>
    /// Class that represents the shell of the OS
    /// </summary>
    class Shell
    {
        /// <summary>
        /// Method that creates a new instance of the Shell
        /// </summary>
        public void Shell_Construct() 
        {
            Console.WriteLine(Prompt());
            string an_instruction;
            do
            {
                while (Scheduler.hasSync())
                {
                    try
                    {
                        Thread.Sleep(15);
                        //put the thread to sleep
                    }
                    catch (Exception) { }
                }
                Console.Write("katOS:>");
                an_instruction = Console.ReadLine();

                if (an_instruction.ToLower().Equals("exit"))
                {
                    break;
                }
                if(an_instruction.Equals(""))
                {
                    Console.WriteLine();
                }
                Parse(an_instruction);

            }
            while (true);
        }

        /// <summary>
        /// Method that shows the prompt information
        /// </summary>
        /// <returns></returns>
        public String Prompt() 
        {
            string welcome = "katOS [Version 1.0]\n" +
                           "GNU General Public License v3 <http://code.google.com/p/karenandys-rep/> \n";
            return welcome;
        }

        /// <summary>
        /// Method that parses what's written on the shell
        /// </summary>
        /// <param name="instruction"></param>
        public void Parse (String instruction)
        {
            instruction = instruction.TrimStart(' ');
            instruction = instruction.TrimEnd(' ');
            instruction = instruction.TrimStart('\t');
            instruction = instruction.TrimEnd('\t');
            while (instruction.Contains("   ")) 
            {
                instruction = instruction.Replace(" "," ");
            }
            IsSystemProgram(instruction);
        }

        /// <summary>
        /// Method that recognizes if the input is a System Program
        /// </summary>
        /// <param name="line_instruction">A line of instruction</param>
        public static bool IsSystemProgram(string line_instruction)
        {
            SystemPrograms a_program = new SystemPrograms();
            //Scheduler a_scheduler = new Scheduler();
            bool isSysProg;
            string[] instruction = line_instruction.Split(' ');
            switch (instruction[0])
            { 
                case "ls":
                    isSysProg = true;
                    a_program.ls();
                    break;
                case "kill":
                    isSysProg = true;
                    a_program.kill(instruction[1]);
                    break;
                case "ps":
                    isSysProg = true;
                    a_program.ps();
                    break;
                case "exit":
                    isSysProg = true;
                    Console.WriteLine("Good bye");
                    //here terminate the threads
                    break;
                case "help":
                    isSysProg = true;
                    Console.WriteLine("Show help"); //TODO
                    break;  
                default:
                    isSysProg = false;
                    typeOfUserProgram(line_instruction);
                    //string file = instruction[0];
                    //a_scheduler.AddProcess(file);
                    break;
            }
            return isSysProg;
        }

        public static void typeOfUserProgram(string instruction)
        {
            bool sync = true;
            int[] parameters = { 0, 0, 0, 0, 0, 0, 0, 0 };
            string out_file_name="";
            string[] part_instruction = instruction.Split(' ');
            string program_file;
            int param_count=0;
            int priority = 4;
            bool is_right = true;
            //Scheduler a_scheduler = new Scheduler();

            if (part_instruction[part_instruction.Length - 1].StartsWith("p") || part_instruction[part_instruction.Length - 1].StartsWith("P"))
            {
                try
                {
                    int priority_value = int.Parse(part_instruction[part_instruction.Length - 1].Substring(1));
                    if (priority_value <= 9 && priority_value >= 0)
                    {
                        priority = priority_value;
                    }

                }
                catch(Exception)
                {
                    is_right = false;
                    Console.WriteLine("Wrong value for priority");
                }
                instruction = instruction.Substring(0,instruction.LastIndexOf(' '));
                part_instruction = instruction.Split(' ');
               // Console.WriteLine("The inst: "+instruction+" priority: "+priority);
            }

            try
            {
                if (instruction.Contains('>'))
                {
                    if (part_instruction[part_instruction.Length - 2].StartsWith(">"))
                    {
                        sync = false;
                        out_file_name = part_instruction[part_instruction.Length - 1];
                        instruction = instruction.Substring(0, instruction.LastIndexOf('>') - 1);
                        part_instruction = instruction.Split(' ');
                    }
                }
            }
            catch(Exception) {}
            //Console.WriteLine("the inst(part2): "+instruction);

            if(part_instruction.Length<=9 && part_instruction.Length>1)
            {
                //bool right_parameters = true;
                for(int i=1; i<part_instruction.Length; i++)
                {
                    try
                    {
                        parameters[param_count] = int.Parse(part_instruction[i]);
                        param_count++;
                    }
                    catch(FormatException)
                    {
                        is_right = false;
                        //right_parameters=false;
                        Console.WriteLine("Incorrect parameters on instruction");
                        break;
                    }

                }

                if(is_right)
                {
                    if (!sync)
                    {
                        program_file = part_instruction[0];
                        Process a_process = new Process(program_file, Scheduler.pc, priority, parameters, out_file_name);
                        Scheduler.pc++;
                        Scheduler.AddProcessToTemp(a_process);
                        //Scheduler.AddProcess(program_file, parameters, out_file_name, priority);
                    }
                    else
                    {
                        program_file = part_instruction[0];
                        Process a_process = new Process(program_file, Scheduler.pc, priority, parameters, out_file_name);
                        Scheduler.pc++;
                        Scheduler.AddProcessToTemp(a_process);
                        //Scheduler.AddProcess(program_file, parameters, priority);
                    }
                    
                }
            }
            if (part_instruction.Length == 1)
            {
                if (!sync)
                {
                    program_file = part_instruction[0];
                    Process a_process = new Process(program_file, Scheduler.pc, priority, out_file_name);
                    Scheduler.pc++;
                    Scheduler.AddProcessToTemp(a_process);
                    //Scheduler.AddProcess(program_file, out_file_name, priority);
                }
                else
                {
                    program_file = part_instruction[0];
                    Process a_process = new Process(program_file, Scheduler.pc, priority);
                    Scheduler.pc++;
                    Scheduler.AddProcessToTemp(a_process);
                    //Scheduler.moveToRealQueue();
                    //Change the add process to temp queue
                    //Scheduler.AddProcess(program_file, priority);
                }
            }
        }
    }
}
